<script setup lang="ts">
import {useSysStore} from "stores/sysStore";
import {ref, onMounted, watch, Ref} from "vue";
// import AgoraRTC from "agora-rtc-sdk-ng";
import RTMCom from "pages/components/RTMCom.vue";
import eventBus from "src/utils/eventBus";
import {useQuasar} from "quasar";
import PageTop from "components/page-top.vue";
import {RTCConfig, TypeRTCConfig, Wss} from "src/utils/type";
import InviteWorker from "pages/components/inviteWorker.vue";
import {createFastboard,mount} from "@netless/fastboard/full";
import CallAgent from "pages/components/callAgent.vue";
import {tips, userBehavior} from "src/utils/util";
import {conf} from "src/utils/APIClient";

//白板的sdk在线上的时候通过CDN的方式引入
// if (process.env.DEV){
//   var createFastboard:any = null;
//   var mount:any = null;
//   import("@netless/fastboard/full").then((res)=>{
//     createFastboard = res.createFastboard;
//     mount = res.mount;
//   })
// }

let prop = defineProps(['role'])
let $q = useQuasar()
let sysStores = useSysStore();
// 声网配置
let rtc: any = {
  localAudioTrack: null,
  localVideoTrack: null,
  client: null,
};
let videoWinList: Ref<any> = ref([{
  name: '自己',
  domId: 'videoAnother0',
  active: false
}])

let RTCConfig:TypeRTCConfig;
onMounted(() => {
  RTCConfig = {
    appId: sysStores.wssMessage.message.app_id,
    channel: sysStores.wssMessage.message.channel_name,
    token: sysStores.wssMessage.message.rtc_token,
    shareToken: sysStores.wssMessage.message.rtc_share_token,
    uid: sysStores.userInfo.id,
    channelInstanceId: sysStores.wssMessage.message.channel_instance_id,
  }
  sysStores.RTCConfig = sysStores.wssMessage.message;//存储RTCConfig用于后续的其他操作
  if (!sysStores.userInfo.id) RTCConfig.uid = localStorage.getItem("userId") as string;
  initRtcConnect();
})

const initRtcConnect = async () => {
  if (process.env.DEV){
     window.AgoraRTC = (await import("agora-rtc-sdk-ng")).default;
  }
  rtc.client = window.AgoraRTC.createClient({mode: "rtc", codec: "vp8"});// 创建AgoraRTC客户端对象
  // 监听远程用户发布事件
  rtc.client.on("user-published", async (user: any, mediaType: string) => {
    try {
      // 订阅远程用户
      await rtc.client.subscribe(user, mediaType);
      console.log("订阅成功", user.uid, mediaType);
      // 如果是视频轨道，播放到video-side容器
      if (mediaType === "video") {
        if (boardConfig.value.roomToken) eventBus.$emit('createBoardSuccess', sysStores.boardConfig) //通知部门工作人员进入白板
        // 等待 Vue 更新 DOM
        appendVideoWin({
          name: user.uid,
          domId: 'videoAnother' + user.uid,
        });
        await new Promise(resolve => setTimeout(resolve, 100));
        const videoSideContainer = document.getElementById(`videoAnother${user.uid}`);
        if (videoSideContainer) user.videoTrack.play(videoSideContainer);
      }
      // 如果是音频轨道，直接播放
      if (mediaType === "audio") user.audioTrack.play();

    } catch (error) {
      console.error(`订阅用户 ${user.uid} 的 ${mediaType} 失败:`, error);
    }
  });

  // 监听远程用户取消发布事件
  rtc.client.on("user-unpublished", (user: any, mediaType: string) => {
    // 如果用户没有任何媒体轨道了，移除用户
    let index = videoWinList.value.findIndex(item => item.name === user.uid);
    if (index != -1) {
      let focusThisWin = videoWinList.value[index].active;//删除该窗口的时候需要考虑用户焦点是否在该窗口上
      videoWinList.value.splice(index, 1);
      if (focusThisWin) videoWinList.value[1].active = true
    }
  });

  // 监听用户离开事件
  rtc.client.on("user-left", (user: any) => {
    // remoteUsers.value = remoteUsers.value.filter(u => u.uid !== user.uid);
  });

  rtc.localVideoTrack = await AgoraRTC.createCameraVideoTrack();//创建本地视频轨道
  rtc.localAudioTrack = await AgoraRTC.createMicrophoneAudioTrack();//创建本地音频轨道
  //预览本地视频轨道
  rtc.localVideoTrack.play(document.getElementById('videoAnother0'));
  // 注意：本地音频轨道通常不应该播放到扬声器，这会造成回音
  // rtc.localAudioTrack.play();

  await rtc.client.join(RTCConfig.appId, RTCConfig.channel, RTCConfig.token, RTCConfig.uid); //加入频道
  await rtc.client.publish([rtc.localAudioTrack, rtc.localVideoTrack]);// 发布本地音视频轨道
  sysStores.channelName = RTCConfig.channel; //存储channel_name用于邀请部门人员的时候服务端需要
}

const notifyDeptWorker = (workerId) => {
  //如果没有白板，则不通知部门
  if (!videoWinList.value.filter(x => {
    return x.name == '白板'
  }).length) return
  //如果对方不是部门 | 如果当前角色不是坐席（存在隐患，多个部门进入的情况）
  if (sysStores.crowdId != workerId && sysStores.userInfo.role_id == 4)
    sysStores.sendWss({
      to: Number(workerId),
      message_type: 'single_message',
      message: 'joinBoard'
    })
}

//视频窗口切换函数
const switchVideo = (win, index) => {
  videoWinList.value.forEach(u => {
    u.active = false
  })
  activeVideoIndex.value = index;
  win.active = true;
}
//-------------------------------------共享屏幕部分的代码如下-------------------------------------
//共享屏幕的触发
let shareRtc: any = {
  shareClient: null,
  shareTrack: null
}

const shareScreen = async () => {
  if (shareRtc.shareClient) return tips.warning($q, '您正在分享屏幕！')
  userBehavior({operation_type_id:'rc_customer_desktop_shared'});
  shareRtc.shareClient = AgoraRTC.createClient({mode: "rtc", codec: "vp8"});// 创建AgoraRTC客户端对象

  shareRtc.shareTrack = await AgoraRTC.createScreenVideoTrack({
    encoderConfig: '1080p_1', // 高清配置
    optimizationMode: 'detail', // 细节优化（适合文档/PPT）
  });
  await shareRtc.shareClient.join(RTCConfig.appId, RTCConfig.channel, RTCConfig.shareToken, RTCConfig.uid + '_share'); //加入频道
  await shareRtc.shareClient.publish([shareRtc.shareTrack]);// 发布共享的视频流

  shareRtc.shareTrack.on("track-ended", () => {
    console.log("屏幕分享被用户手动停止");
    // 这里可选择直接离开频道或仅停止分享
    stopScreenShareAndLeave();
  });

  async function stopScreenShareAndLeave() {
    shareRtc.shareTrack.stop();
    await shareRtc.shareClient.unpublish(shareRtc.shareTrack); // 仅停止发布，轨道仍需手动关闭\
    await shareRtc.shareClient.leave();
    shareRtc.shareClient = null
    shareRtc.shareTrack = null
  }
}

//计算左上角的小窗口的位置
let activeVideoIndex = ref(0) // 当前主窗口的视频索引
const countLeft = (index: number) => {
  let left = 0;
  if (index <= activeVideoIndex.value) {
    left = (160 * index) + (20 * index)
  } else {
    left = (160 * (index - 1)) + (20 * (index - 1));
  }
  return left + 20 + 'px'
}

/**
 * --------------------------------------------以下代码是白板部分的创建和控制-------------------------------------
 * 如果是被通知加入房间的，从rtm收到room信息后，会手动添加sysStores.wssMessage，以便于触发白板的watch
 */
interface Board {
  appIdentifier: string
  roomToken: string
  region: string
  uuid: string
}

let boardConfig: Board | {} = ref({});

watch(() => sysStores.wssMessage, (newVal) => {
  let msg: Wss = (newVal as Wss);
  //创建白板成功，进入白板
  if (msg.message_type == 'create_room_resp') {
    boardConfig.value = {
      appIdentifier: sysStores.wssMessage.message.appIdentifier,
      roomToken: sysStores.wssMessage.message.roomToken,
      region: sysStores.wssMessage.message.region,
      uuid: sysStores.wssMessage.message.uuid,
    }
    renderFastboard();
  }
}, {
  deep: true,
})

//开始创建白板。点击创建白板按钮（需判断是否已创建白板）
let boardLaunch = false; //用来标记是自己主动创建的白板，就需要自己去通过rtm通知其他人
const beginCreateBoard = () => {
  if (boardConfig.value.roomToken) return tips.warning($q, '您已在白板中')
  boardLaunch = true;
  sysStores.sendWss({
    message_type: 'create_room',
  })
}


let fastBoardApp: any;
const renderFastboard = async () => {
  async function mountFastboard(div: HTMLElement | null) {
    fastBoardApp = await createFastboard({
      sdkConfig: {
        appIdentifier: boardConfig.value.appIdentifier,
        region: boardConfig.value.region,
      },
      joinRoom: {
        uid: sysStores.userInfo.id + '', //白板token是通用的，但是加入的时候需要用自己的id加入
        uuid: boardConfig.value.uuid,
        roomToken: boardConfig.value.roomToken,
      },
      managerConfig: {
        cursor: true,
      },
    });
    mount(fastBoardApp, (div as HTMLDivElement));
  }

  appendVideoWin({
    name: '白板',
    domId: 'anotherBoard',
  });
  await new Promise(resolve => setTimeout(resolve, 100));
  mountFastboard(document.getElementById("anotherBoard"));
  sysStores.boardConfig = boardConfig.value;

  //白板创建成功后以后，通知频道中的其他人进入白板,在RTM中监听该事件，以便于发送消息到channel中
  //请注意，只有自己创建白板房间才需要通知其他人，如果是被通知加入的，不需要再通知别人了
  if (boardLaunch) eventBus.$emit('sendBoardConfig', boardConfig.value)
}

//上传文件到白板中
const uploadToBoard = async () => {
  (document.getElementById('file') as HTMLDivElement).click()
}

eventBus.$on('uploadFileDown', (res) => {
  let token = localStorage.getItem('token');
  fastBoardApp.insertImage(`${conf.host}/user/image/get?path=${res.FileList[0]}&token=${token}`)
  userBehavior({
    operation_type_id:'uploadShareDocument',
    operation_content:res.FileList[0]
  })
});

//---------------------------------------退出所有的服务和一些辅助类的方法-------------------------------------------------
eventBus.$on('unloadPage', () => {
  quitAllService();
})
const quitAllService = async () => {
  $q.notify({
    message: '确认退出房间吗？',
    color: 'warning',
    textColor: 'black',
    position: "center",
    icon: 'cancel_presentation',
    actions: [
      {
        label: '确认', color: 'black', handler: async () => {
          rtc.localAudioTrack?.close();
          rtc.localAudioTrack = null;

          rtc.localVideoTrack?.close();
          rtc.localVideoTrack = null;

          shareRtc.shareTrack?.clone()
          shareRtc.shareTrack = null;

          eventBus.$emit('leaveChannel')//离开RTM频道
          await shareRtc.shareClient?.leave() //视频分享离开RTC频道
          await rtc.client?.leave();//离开RTC频道
          fastBoardApp?.dispose();//离开白板房间
        }
      },
      {
        label: '取消', color: 'white', handler: () => {

        }
      }
    ]
  })
}

const appendVideoWin = (para) => {
  videoWinList.value.forEach(win => {
    win.active = false
  })
  videoWinList.value.push({
    ...para,
    active: true,
  });
  activeVideoIndex.value = videoWinList.value.length - 1;
}

//邀请部门人员
let inviteWorker: any = ref(null)
const inviteWorkerFn = () => {
  inviteWorker.value.openDialog();
}

//调用智能问答
let callAgent: any = ref(null)
const callAgentFn = () => {
  callAgent.value.openDialog();
}

//--------------------------工作人员向群众发起邀请  邀请对方分享桌面 | 邀请对方再白板中上传文件 | 邀请对方--------------------------
const commandCrowd = (command: string) => {
  eventBus.$emit('sendCommand', command)
}
eventBus.$on('receiveCommand', async (command: string) => {
  let message = {
    shareToChannel: '工作人员邀请你进行屏幕共享',
    uploadFileToBoard: '工作人员邀请你向白板中上传文件',
  }
  if (!message[command]) return;
  $q.notify({
    message: message[command],
    color: 'blue-8',
    position: "center",
    multiLine: true,
    timeout: 15000,
    textColor: 'white',
    icon: 'screen_share',
    actions: [
      {
        label: '接受', color: 'white', handler: async () => {
          if (command == 'shareToChannel') shareScreen();
          if (command == 'uploadFileToBoard') uploadToBoard();
        }
      },
      {
        label: '拒绝', color: 'black', handler: () => {
          //todo
        }
      }
    ]
  })
})


</script>

<template>
  <div class="calling-out">
    <div class="calling-top" v-if="!prop.role">
      <page-top></page-top>
    </div>
    <div class="calling-con">
      <div class="con-center">
        <div class="left">
          <div class="video-com" id="videoDom">
            <div
              v-for="(item, index) in videoWinList" :key="index"
              :class="['videoAnother', `videoAnother${index}`, { 'active': item.active }]"
              :style="{left:countLeft(index)}" :id="item.domId" @click="switchVideo(item,index)">
              <span class="name">{{ item.name }}</span>
            </div>
            <div class="operate">
              <q-icon class="invite" name="file_present" @click="commandCrowd('uploadFileToBoard')"
                      v-show="sysStores.userInfo.role_id!=1 && boardConfig.roomToken">
                <q-tooltip>邀请上传文件到白板</q-tooltip>
              </q-icon>
              <q-icon class="invite" name="preview" @click="commandCrowd('shareToChannel')"
                      v-show="sysStores.userInfo.role_id!=1">
                <q-tooltip>邀请群众分享屏幕</q-tooltip>
              </q-icon>
              <div class="line"></div>
              <q-icon name="cloud_upload" @click="uploadToBoard" v-show="boardConfig.roomToken">
                <q-tooltip>上传文件到白板</q-tooltip>
              </q-icon>
              <q-icon name="tips_and_updates" @click="callAgentFn" v-show="sysStores.userInfo.role_id!=1">
                <q-tooltip>智能问答</q-tooltip>
              </q-icon>
              <q-icon name="edit_document" @click="beginCreateBoard" v-show="sysStores.userInfo.role_id!=1">
                <q-tooltip>创建白板</q-tooltip>
              </q-icon>
              <q-icon name="screen_share" @click="shareScreen">
                <q-tooltip>分享屏幕</q-tooltip>
              </q-icon>
              <q-icon name="group_add" @click="inviteWorkerFn" v-show="sysStores.userInfo.role_id!=1">
                <q-tooltip>邀请部门工作人员</q-tooltip>
              </q-icon>
              <q-icon name="cancel_presentation" @click="quitAllService">
                <q-tooltip>退出/结束</q-tooltip>
              </q-icon>
            </div>
          </div>
        </div>
        <div class="right">
          <RTMCom></RTMCom>
        </div>
      </div>
    </div>
  </div>
  <invite-worker ref="inviteWorker"/>
  <keep-alive>
    <call-agent ref="callAgent"/>
  </keep-alive>
</template>

<style scoped lang="scss">
.calling-out {
  width: 100%;
}

.calling-con {
  width: 100%;
  min-width: 1400px;
  height: calc(100vh - 80px);
  display: flex;
  justify-content: center;
  align-items: center;

  .con-center {
    width: calc(100% - 20px);
    height: 100%;
    display: flex;
    justify-content: space-between;

    .left {
      width: calc(100% - 390px);
      height: 100%;
      position: relative;

      .min {
        width: 97% !important;
        height: 97% !important;
      }

      .video-com {
        height: 100%;
        width: 100%;
        border-radius: 10px;
        position: absolute;
        left: 0;
        bottom: 0;
        z-index: 999;
        background-image: linear-gradient(-225deg, #CBBACC 0%, #2580B3 100%);

        .videoAnother {
          position: absolute;
          background-color: #333;
          border: 2px solid #666;
          cursor: pointer;
          transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);

          .name {
            position: absolute;
            right: 10px;
            bottom: 10px;
            padding: 1px 10px;
            border-radius: 20px;
            color: black;
            background-color: white;
            font-size: 12px;
            z-index: 999;
          }

          &:not(.active) {
            width: 160px;
            height: 90px;
            top: 20px;
            z-index: 10;

            //&:nth-child(1) { left: 10px; }
            //&:nth-child(2) { left: 170px; }
            //&:nth-child(3) { left: 330px; }
            //&:nth-child(4) { left: 490px; }

            &:hover {
              transform: scale(1.05);
              border-color: #0078d4;
            }
          }

          &.active {
            width: 100%;
            height: 100%;
            top: 0 !important;
            left: 0 !important;
            z-index: 1;
            border: none;
          }
        }

        .operate {
          width: 100%;
          height: 100px;
          position: absolute;
          bottom: 0;
          left: 0;
          background: linear-gradient(to top, rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 0.9) 10%, rgba(0, 0, 0, 0.9) 20%, rgba(0, 0, 0, 0.8) 40%, rgba(0, 0, 0, 0.7) 60%, rgba(0, 0, 0, 0.2) 80%, rgba(0, 0, 0, 0.1) 90%, rgba(0, 0, 0, 0) 100%);
          backdrop-filter: blur(2px);
          -webkit-backdrop-filter: blur(2px);
          display: flex;
          justify-content: end;
          align-items: center;
          z-index: 20;

          .invite {
            color: #ffb842;
          }

          i {
            font-size: 36px;
            //font-weight: bold;
            color: white;
            margin: 0 15px;
            position: relative;
            transition: all .2s ease;
            cursor: pointer;
            top: 20px;
          }

          i:hover {
            transition: all .2s ease;
            transform: scale(1.2);
          }
        }
      }
    }

    .right {
      width: 390px;
      height: 100%;
      background-image: linear-gradient(to top, #e6e9f0 0%, #eef1f5 100%);
    }
  }

}
</style>
